#include "Server.h"

Server::Server():log(CommonFunctions::GetLogName()){
	log.activeDebug(true);
	this->serverQueue = new Queue<message>(CommonFunctions::GetServerQueue().c_str(), 'a');
	SignalHandler::getInstance()->registrarHandler(SIGINT,&sigint_handler);
	debug("");
	debug("********************************************************************************");
	debug("");
	debug("Servidor iniciado");
}

void Server::run(){
	 while (sigint_handler.getGracefulQuit() == 0) {
			message msgIN = receiveMessage();
			message msgOUT;

			switch (msgIN.commandId){
				case CONECTAR:
					msgOUT = connectClient(msgIN.clientId, msgIN.text);
					break;
				case INICIAR_CONVERSACION:
					msgOUT = createGroupChat(msgIN.clientId, msgIN.text);
					break;
				case UNIRSE_CONV:
					msgOUT = joinGroupChat(msgIN.clientId, msgIN.text);
					break;
				case DEJAR_CONV:
					msgOUT = leftGroupChat(msgIN.clientId, msgIN.groupChatId);
					break;
				case PARTIC_ACTIVOS:
					msgOUT = showPeopleInGroupChat(msgIN.clientId, msgIN.text);
					break;
				case CONV_ACTIVAS:
					msgOUT = showActiveGroupsChat(msgIN.clientId);
					break;
				case DESCONECTAR:
					msgOUT = disconnectClient(msgIN.clientId);
					break;
				case CONVERSAR:
					msgOUT = talkGroupChat(msgIN.clientId, msgIN.groupChatId, msgIN.text);
					break;
			}
			sendMessage(msgOUT);
	};
	SignalHandler::getInstance()->destruir();
}

message Server::receiveMessage(){
	message msg;
	int response = this->serverQueue->read( REQUEST, &msg );
	
	if ( response < 0 )
	{
		cerr << "Error leyendo pedido" << endl;
	}
	return msg;
}

void Server::sendMessage(message msg){
	int response = this->serverQueue->write(msg);
	if ( response < 0 )
	{
		cerr << "Error enviando respuesta" << endl;
	}
}

message Server::connectClient(int pid, string nick){
	debug("Procesando pedido de CONECTAR al servidor solicitada por " + CommonFunctions::ToString(pid));
	User* user = new User(pid, nick);
	clients.push_back(user);
	debug("Se agrego el participante con id " + CommonFunctions::ToString(pid) + " bajo el nick " + nick);
	return ackMessage(pid, 0, "ack");
}

message Server::disconnectClient(int pid){
	debug("Procesando pedido de DESCONECTAR solicitada por " + CommonFunctions::ToString(pid));
	for (vector<User*>::iterator it = clients.begin(); it != clients.end(); ++it) {
		if ( (*it)->getUserId() == pid ){
			debug("Se desconecto el participante con id " + CommonFunctions::ToString(pid) + " bajo el nick " + (*it)->getNick() );
			//clients.erase(it);
		}
	}
	return ackMessage(pid, 0, "ack");
}

message Server::createGroupChat(int pid, string name){
	debug("Procesando pedido de INICIAR_CONVERSACION solicitada por " + CommonFunctions::ToString(pid));
	debug("Nombre del group chat a crear: " + name);
	User* user = getUser(pid);
	if ( user != NULL ){
		GroupChat* group = new GroupChat(pid, name);
		group->join(user);
		groups.push_back(group);
		debug("Se agrego el participante " + user->getNick() + " al grupo " + group->getName() );
	}
	return ackMessage(pid, pid, "ack");
}

message Server::joinGroupChat(int pid, string name){
	debug("Procesando pedido de UNIRSE_CONVERSACION solicitada por " + CommonFunctions::ToString(pid));
	debug("Nombre del group chat al que desea unirse: " + name);
	int groupId = 0;
	User* user = getUser(pid);
	for (vector<GroupChat*>::iterator it = groups.begin(); it != groups.end(); ++it)
	{
		if ( strcmp((*it)->getName().c_str(), name.c_str()) == 0 )
		{
			(*it)->join(user);
			groupId = (*it)->getId();
			(*it)->instantMessaging(pid,"El participante " + user->getNick() + " se unio exitosamente al grupo " + (*it)->getName());
			debug("El participante " + user->getNick() + " se unio exitosamente al grupo " + (*it)->getName());
			break;
		}
	}
	if ( groupId == 0 ){
		debug("No existe el grupo " + name );
	}
	return ackMessage(pid, groupId, "ack");
}

message Server::leftGroupChat(int pid, int gpid){
	debug("Procesando pedido de DEJAR_CONVERSACION solicitada por " + CommonFunctions::ToString(pid));
	User* user = getUser(pid);
	GroupChat* groupChat = getGroupChat(gpid);
	if ( groupChat != NULL && user != NULL){
		debug("Eliminando participante " + user->getNick() + " de la conversacion " + groupChat->getName());
		groupChat->left(user);

		if(groupChat->isEmpty() ){
			debug("La conversación " + groupChat->getName()+ " se ha eliminado por falta de participantes");
			//Eliminando la conversacion del vector groups
			eraseGroupChat(gpid);
			//Eliminando el puntero
			delete groupChat;
		}
		else{
		groupChat->instantMessaging(pid,"El participante " + user->getNick() + " abandonó la conversacion " + groupChat->getName());
		}
	}
	return ackMessage(pid, gpid, "ack");
}

void Server::eraseGroupChat(int gpid){
	for (vector<GroupChat*>::iterator it = groups.begin(); it != groups.end(); ++it) {
			if ( (*it)->getId() == gpid ) {
				groups.erase(it);
				break;
			}
		}
}

message Server::talkGroupChat(int pid, int gpid, string text){
	debug("Procesando pedido de CONVERSAR solicitada por " + CommonFunctions::ToString(pid));
	debug("El participante "  + CommonFunctions::ToString(pid) + " envia mensaje >> " + text );

	GroupChat* groupChat = getGroupChat(gpid);

	if ( groupChat != NULL){
		debug("Enviando mensaje al grupo " + groupChat->getName());
		groupChat->instantMessaging(pid, text);
	}
	return ackMessage(pid, gpid, "ack");
}

message Server::showActiveGroupsChat(int pid){
	debug("Procesando pedido de CONVERSACIONES_ACTIVAS solicitada por " + CommonFunctions::ToString(pid));
	string allGroups;
	for (vector<GroupChat*>::iterator it = groups.begin(); it != groups.end(); ++it)
	{
		allGroups += (*it)->getName() + " , ";
	}
	debug("Los grupos activos son " + allGroups);
	return ackMessage(pid, 0, allGroups);
}

message Server::ackMessage(int pid, int gpid, string txt){
	debug("Va a enviar ack con texto " + txt + " a participante " + CommonFunctions::ToString(pid));
	message msg;
	msg.mtype = pid;
	msg.clientId = pid;
	msg.commandId = OK;
	msg.groupChatId = gpid;
	strcpy( msg.text, txt.c_str() );
	return msg;
}

message Server::showPeopleInGroupChat(int pid, string gp){
	string people;
	GroupChat* groupChat = NULL;
	debug("Procesando pedido de PARTICIPANTES_ACTIVOS en el group chat " + gp + " solicitada por " + CommonFunctions::ToString(pid));
	for (vector<GroupChat*>::iterator it = groups.begin(); it != groups.end(); ++it) {
		if ( (*it)->getName() == gp ){
			groupChat = (*it);
		}
	}

	if ( groupChat != NULL ){
		people = groupChat->usersConnected();
		debug("Participantes activos en group chat " + groupChat->getName() + ":" + people);
	}
	else {
		debug("No existe el group chat " + gp);
	}
	return ackMessage(pid, 0, people);
}


User* Server::getUser(int pid){
	for (vector<User*>::iterator it = clients.begin(); it != clients.end(); ++it) {
		if ( (*it)->getUserId() == pid ){
			return (*it);
		}
	}
	return NULL;
}

GroupChat* Server::getGroupChat(int gpid){
	for (vector<GroupChat*>::iterator it = groups.begin(); it != groups.end(); ++it) {
		if ( (*it)->getId() == gpid ){
			return (*it);
		}
	}
	return NULL;
}

void Server::debug(string line){
	log.debug("[server] " + line + "\n");
}

Server::~Server(){
	delete this->serverQueue;
	//Borrando punteros a las conversaciones
	for(vector<GroupChat*>::iterator it = this->groups.begin(); it != this->groups.end(); it++){
		delete *it;
	}
	//Borrando punteros a los usuarios
	for(vector<User*>::iterator it2 = this->clients.begin(); it2 != this->clients.end(); it2++){
			delete *it2;
		}
	debug("Servidor finalizado");
}

